package com.eight.cloud.payment.core.wechat.channel;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.eight.cloud.client.model.vo.RefundVo;
import com.eight.cloud.core.global.model.BaseUser;
import com.eight.cloud.core.utils.supply.UserContext;
import com.eight.cloud.payment.config.WechatServiceProviderConfig;
import com.eight.cloud.payment.core.IPaymentStrategy;
import com.eight.cloud.payment.model.vo.MerchantAppVo;
import com.eight.cloud.payment.model.vo.SubRefundOrderVo;
import com.eight.cloud.payment.service.IMerchantAppService;
import com.eight.cloud.redisson.utils.RedisUtils;
import com.google.gson.Gson;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.QueryByOutRefundNoRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import lombok.extern.slf4j.Slf4j;

import static com.eight.cloud.payment.common.constant.CacheConstant.PAY_NOTIFY_URL_CACHE_KEY;
import static com.eight.cloud.payment.common.constant.CacheConstant.generateKey;


/**
 * @ClassName: WxPay
 * @Description: 微信支付抽象类
 * @Author: TXC
 * @Date: 2024-12-26 14:42
 **/
@Slf4j
public abstract class WxPay implements IPaymentStrategy {
    private final RSAAutoCertificateConfig rsaAutoCertificateConfig;
    private final WechatServiceProviderConfig wechatServiceProviderConfig;
    private final RedisUtils redisUtils;
    private final IMerchantAppService merchantAppService;
    public final static String PAR_NOTIFY_URL = "/pay/notice/payment/wechat/notify_url";
    public final static String PAY_REFUND_NOTIFY_URL = "/pay/notice/payment/wechat/refund/notify_url";
    public final static Gson gson = new Gson();

    public WxPay(RSAAutoCertificateConfig rsaAutoCertificateConfig,
                 WechatServiceProviderConfig wechatServiceProviderConfig, RedisUtils redisUtils,
                 IMerchantAppService merchantAppService) {
        this.rsaAutoCertificateConfig = rsaAutoCertificateConfig;
        this.wechatServiceProviderConfig = wechatServiceProviderConfig;
        this.redisUtils = redisUtils;
        this.merchantAppService = merchantAppService;
    }


    /**
     * 退款
     *
     * @param refundOrder 退款金额(单位为分)
     * @param notifyUrl 回调地址
     * @return 结果
     */
    @Override
    public String refund(SubRefundOrderVo refundOrder, String notifyUrl) {
        RefundService service = new RefundService.Builder().config(rsaAutoCertificateConfig).build();
        CreateRequest request = new CreateRequest();
        request.setOutRefundNo(refundOrder.getUuid());
        request.setOutTradeNo(refundOrder.getOutTradeNo());
        AmountReq amountReq = new AmountReq();
        // 设置退款金额（退款金额不可大于订单金额）单位为分
        try {
            amountReq.setRefund(refundOrder.getRefund());
            // 订单总金额
            amountReq.setTotal(refundOrder.getTotal());
        } catch (NumberFormatException e) {
            throw new RuntimeException("金额需要是以分为单位的整数", e);
        }
        amountReq.setCurrency("CNY");
        amountReq.setFrom(null);
        request.setAmount(amountReq);
        request.setSubMchid(refundOrder.getMerchantId());
        request.setNotifyUrl(wechatServiceProviderConfig.getNotifyServiceUrl() + PAY_REFUND_NOTIFY_URL);
        try {
            Refund result = service.create(request);
            if (StrUtil.isNotEmpty(notifyUrl)) {
                cacheClientNotifyUrl(refundOrder.getUuid(), notifyUrl);
            }
            result.setOutTradeNo(refundOrder.getSubOutTradeNo());
            return JSONUtil.parse(result).toStringPretty();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    @Override
    public RefundVo queryByOutRefundNo(SubRefundOrderVo subRefundOrder) {
        RefundService service = new RefundService.Builder().config(rsaAutoCertificateConfig).build();
        QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
        request.setOutRefundNo(subRefundOrder.getUuid());
        request.setSubMchid(subRefundOrder.getMerchantId());
        Refund refund = service.queryByOutRefundNo(request);
        RefundVo refundVo = new RefundVo();
        BeanUtil.copyProperties(refund, refundVo);
        return refundVo;
    }

    public MerchantAppVo getAccount(String subMerchantId) {
        BaseUser app = UserContext.getUser();
        if (ObjectUtil.isNull(app)) {
            throw new RuntimeException("应用未授权");
        }
        MerchantAppVo merchant;
        if (StrUtil.isNotEmpty(subMerchantId)) {
            merchant = merchantAppService.getAuthorizeApp(app.getUuid(), subMerchantId);
        } else {
            throw new RuntimeException("商户信息不存在");
        }
        return merchant;
    }

    public void cacheClientNotifyUrl(String orderId, String notifyUrl) {
        redisUtils.set(generateKey(PAY_NOTIFY_URL_CACHE_KEY, orderId), notifyUrl, 600L);
    }

}
